
#include "PortManager.h"
#include "ThreadManager.h"
#include <iostream>
#include <time.h>
#include <stdlib.h>
#include <unistd.h>
#include <map>
#include <string>
#include <fstream>
#include <map>
#include <vector>
#include <sstream>
#include <algorithm>
#include <iterator>     //istreambuf_iterator
#include <stdio.h>

#define random(x) (rand()%x)

using namespace std;
using namespace rapidjson;

typedef map<string, int> Service_Port_Map;

void ufw_allow_port(int port)
{
	std::stringstream ss;
	ss << "sudo ufw allow " << port;
	std::string str = ss.str();
	system(str.c_str());

}

void ufw_forbit_port(int port)
{
	std::stringstream ss;
	ss << "sudo ufw delete allow " << port;
	std::string str = ss.str();
	system(str.c_str());
}

string createJson(Service_Port_Map service_port_map, string clientid)
{
	Document doc;
	Document::AllocatorType &allocator = doc.GetAllocator();
	doc.SetObject();

	Value _client_id;
	_client_id.SetString(clientid.c_str(), clientid.size(), allocator);
	doc.AddMember("clientID", _client_id, allocator);

	Value port_info_array(kArrayType);	//生成一个数组
	Service_Port_Map::iterator itr = service_port_map.begin();
	for (; itr != service_port_map.end(); ++itr)
	{
		int port = itr->second;
		string service_name = itr->first;

		Value port_info(kObjectType);
		Value name;
		name.SetString(service_name.c_str(), service_name.size(), allocator);
		port_info.AddMember("port", port, allocator);
		port_info.AddMember("serviceName", name, allocator);

		port_info_array.PushBack(port_info, allocator);
	}

	doc.AddMember("portInfo", port_info_array, allocator);

	//生成string
	StringBuffer buffer;
	Writer<StringBuffer> writer(buffer);
	doc.Accept(writer);

	string result = buffer.GetString();

	return result;
}

bool srvPortIsUsed(int port)
{
	//std::stringstream srm;
	std::stringstream ss;
	ss << "sudo lsof -i:" << port << " > srvPortIsUsed.txt";
	std::string str = ss.str();
	//cout<<"cmd: "<<str<<endl;
	popen(str.c_str(), "r");
	system(str.c_str());
	//sleep(5);
	std::ifstream _in("srvPortIsUsed.txt", std::ifstream::in);
	std::string line;
	std::getline(_in, line);
	std::getline(_in, line);
	if (!line.empty())
	{
		std::cout << "Port: " << port << " in used" << std::endl;
		return true;
	}
	else {
		std::cout << "Port: " << port << " not in used" << std::endl;
		return false;
	}
}

void CPortManager::start()
{

}

int CPortManager::setID(int id)
{
	m_id = id;
	return 0;
}

int CPortManager::getID()
{
	return m_id;
}

//int CPortManager::send2ThreadbyID(int data, int ID)
//{
//    map<int, Theron::Address>::iterator iter;
//    iter = ThreadManager::instance()->ID_ADDRESS_MAP.find(ID);
//    if (iter != ThreadManager::instance()->ID_ADDRESS_MAP.end())
//    {
//        Send(data, iter->second);
//        return 0;
//    }
//
//    return -1;
//}
void CPortManager::handleMQTTJson(const std::string& json, const Theron::Address from)
//void CPortManager::handleMQTTJson(const MQTTJson& json, const Theron::Address from)
{
	printf("Begin to handleMQTTJson\n");

	string json_data = json;
	string client_id = "";

	StringStream s(json_data.c_str());
	Document doc;
	doc.ParseStream(s);

	if (doc.HasParseError()) {
		cout << "Parse json failed." << endl;
		return;
	}
	if (doc.HasMember("clientID")) {
		client_id = doc["clientID"].GetString();
		cout << "client id: " << client_id << endl;
	}
	if (doc.HasMember("portInfo")) {
		Value port_info;
		port_info = doc["portInfo"];

		Value info;
		Service_Port_Map service_port_map;
		vector<int> port_wanted;    //just save the port that are wanted
		int port_old;   //the original port that want
		for (int i = 0; i < port_info.Size(); ++i) {
			info = port_info[i];
			int port;
			string name;
			if (info.HasMember("port")) {
				port = info["port"].GetInt();
				cout << "port: " << port << endl;
			}
			if (info.HasMember("serviceName")) {
				name = info["serviceName"].GetString();
				cout << "name: " << name << endl;
			}
			port_wanted.push_back(port);
			service_port_map.insert(pair<string, int>(name, port));
		}

		//judge whether the port is used
		Service_Port_Map::iterator itr = service_port_map.begin();
		for (; itr != service_port_map.end(); ++itr) {
			int port = itr->second;
			port_old = port;
			while (1) {
				bool ret = srvPortIsUsed(port);
				if (ret)//port is used
				{
					port++;
					while (1)
					{
						vector<int>::iterator it = find(port_wanted.begin(), port_wanted.end(), port);
						if (it != port_wanted.end())//find
						{
							port++;
						}
						else//not find
							break;
					}
				}
				else {//port is not used
					itr->second = port;
					vector<int>::iterator it = find(port_wanted.begin(), port_wanted.end(), port_old);
					*it = port;
					break;
				}
			}

		}
		itr = service_port_map.begin();
		for (; itr != service_port_map.end(); ++itr) {
			cout << "Ufw allow" << endl;
			cout << "service: " << itr->first;
			cout << " port " << itr->second << endl;
			ufw_allow_port(itr->second);
		}

		string jsonSend = createJson(service_port_map, client_id);
		MQTTResult res;
		res.client_id = client_id;
		res.json = jsonSend;
		sendMQTTResult2ThreadbyID(res, THREAD_MQTTPUB);
		return;
	}
	return;
}

int CPortManager::sendMQTTResult2ThreadbyID(MQTTResult data, int ID)
{
	map<int, Theron::Address>::iterator iter;
	iter = CDataCenter::instance()->ID_ADDRESS_MAP.find(ID);
	if (iter != CDataCenter::instance()->ID_ADDRESS_MAP.end())
	{
		Send(data, iter->second);
		return 0;
	}

	return -1;
}